package taskmaster.util;


/**
 * Sonic Message Manager is a JMS Test Client replacement with
 * ease of use as the primary design goal.
 *
 * Copyright 2008, Gerco Dries (gdr@progaia-rs.nl).
 *
 * Sonic Message Manager is free software: you can redistribute it
 * and/or modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, either version 2 of
 * the License, or (at your option) any later version.
 *
 * Sonic Message Manager is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Sonic Message Manager.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

import javax.swing.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
/**
 * JTextArea with search option. The search option is enabled by default.
 * <p>
 * <code>F3</code> or <code>CTRL-F</code> pops up the search dialog. When
 * something was found or selected, <code>F3</code> looks for the next
 * occurance of the selected text.
 * <p>
 * When the <code>JSearchableTextArea</code> is not editable, the user can
 * type to directly search for the typed text.
 *
 * @author Gerco Dries (gdr@progaia-rs.nl)
 *
 */
public class JSearchableTextArea extends JTextArea {
        private boolean searchEnabled;
        /**
         * Create a new JSearchableTextArea with the search function enabled.
         */
        public JSearchableTextArea() {
                setSearchEnabled(true);
        }

        /**
         * Return whether the search function is enabled.
         *
         * @return
         */
        public boolean isSearchEnabled() {
                return searchEnabled;
        }
        /**
         * Enable or disable the search function.
         *
         * @param searchEnabled
         */
        public void setSearchEnabled(boolean searchEnabled) {
                this.searchEnabled = searchEnabled;
                if(isSearchEnabled()) {
                        enableSearch();
                }
        }

        /**
         * Enable the search function (registers the keylistener).
         */
        private void enableSearch() {
                addKeyListener(new SearchKeyAdapter(this));
        }

        /**
         * Key adapter that implements the actual search function.
         *
         * @author Gerco Dries (gdr@progaia-rs.nl)
         *
         */
        private class SearchKeyAdapter extends KeyAdapter {
                private final JTextArea textArea;

                /**
                 * Create a new SearchKeyAdapter for the indicated TextArea.
                 * @param textArea
                 */
                public SearchKeyAdapter(final JTextArea textArea) {
                        this.textArea = textArea;
                }

                /**
                 * When <code>F3</code> or <code>CTRL-F</code> is pressed, ask for
                 * search input and search.
                 */
                @Override
                public void keyPressed(KeyEvent e) {
                        if(e.getKeyCode() == KeyEvent.VK_F3 && e.getModifiers() == 0) {
                                String searchString = textArea.getSelectedText();
                                if(searchString == null || searchString.length() == 0) {
                                        searchString = getSearchString(searchString);
                                }
                                search(searchString, textArea.getSelectionEnd()+1);
                        }

                        if(e.getKeyCode() == KeyEvent.VK_F && e.isControlDown()) {
                                String searchString = textArea.getSelectedText();
                                searchString = getSearchString(searchString);
                                search(searchString, 0);
                        }
                }

                /**
                 * If the textArea is not editable, perform "search-as-you-type".
                 */
                @Override
                public void keyTyped(KeyEvent e) {
                        // If the textArea is editable, ignore keystrokes
                        if(textArea.isEditable()) {
                                return;
                        }

                        if(e.getKeyChar() == KeyEvent.VK_BACK_SPACE
                        || e.getKeyChar() == KeyEvent.VK_DELETE
                        || e.getKeyChar() == KeyEvent.VK_ENTER
                        || e.getKeyChar() == KeyEvent.VK_ESCAPE) {
                                textArea.select(0,0);
                        }

                        String searchString = textArea.getSelectedText();

                        if(searchString == null)
                                searchString = "";

                        if(!e.isActionKey()) {
                                searchString += e.getKeyChar();
                        }

                        search(searchString, textArea.getSelectionStart());
                }

                /**
                 * Ask for user input.
                 *
                 * @param def
                 * @return
                 */
                private String getSearchString(String def) {
                        if(def == null)
                                def = "";
                        return JOptionPane.showInputDialog("Find...", def);
                }

                /**
                 * Search for the searchString, starting from startPosition. If the
                 * text is found, select it.
                 *
                 * @param searchString
                 * @param startPosition
                 */
                private void search(String searchString, int startPosition) {
                        if(searchString != null && searchString.length() > 0) {
                                searchString = searchString.toLowerCase();

                                // Find the first occurance at or after the current
                                // start position and select it.
                                int position = textArea.getText().toLowerCase().indexOf(
                                                searchString,
                                                Math.max(startPosition, 0));
                                if(position >= 0) {
                                        textArea.select(position, position + searchString.length());
                                } else if (startPosition > 0) {
                                        // If not found and we were searching from a non-zero
                                        // start position, retry from the top.
                                        search(searchString, 0);
                                }
                        }
                }
        }
}
